use cargo::ops;
use cargo::core::MultiShell;
-use cargo::util::{CliResult, CliError, CargoError};
+use cargo::util::{CliResult, CliError, Human};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
#[deriving(RustcDecodable)]
Some(err) => {
Err(match err.exit {
Some(ExitStatus(i)) => CliError::new("", i as uint),
- _ => CliError::from_boxed(err.concrete().mark_human(), 101)
+ _ => CliError::from_boxed(box Human(err), 101)
})
}
}
use cargo::core::MultiShell;
-use cargo::util::{CliResult, CliError, human, Require};
+use cargo::util::{CliResult, CliError, human, ChainError};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
#[deriving(RustcDecodable)]
let root = try!(find_root_manifest_for_cwd(flags.flag_manifest_path));
let string = try!(root.as_str()
- .require(|| human("Your project path contains characters \
- not representable in Unicode"))
+ .chain_error(|| human("Your project path contains \
+ characters not representable in \
+ Unicode"))
.map_err(|e| CliError::from_boxed(e, 1)));
Ok(Some(ProjectLocation { root: string.to_string() }))
use cargo::ops;
use cargo::core::MultiShell;
-use cargo::util::{CliResult, CliError, CargoError};
+use cargo::util::{CliResult, CliError, Human};
use cargo::util::important_paths::{find_root_manifest_for_cwd};
#[deriving(RustcDecodable)]
Some(err) => {
Err(match err.exit {
Some(ExitStatus(i)) => CliError::new("", i as uint),
- _ => CliError::from_boxed(err.concrete().mark_human(), 101)
+ _ => CliError::from_boxed(box Human(err), 101)
})
}
}
use semver;
+use std::error::{Error, FromError};
use std::hash::Hash;
use std::sync::Arc;
use std::fmt::{mod, Show, Formatter};
impl<E, D: Decoder<E>> Decodable<D, E> for PackageId {
fn decode(d: &mut D) -> Result<PackageId, E> {
- let string: String = raw_try!(Decodable::decode(d));
+ let string: String = try!(Decodable::decode(d));
let regex = Regex::new(r"^([^ ]+) ([^ ]+) \(([^\)]+)\)$").unwrap();
let captures = regex.captures(string.as_slice()).expect("invalid serialized PackageId");
InvalidNamespace(String)
}
-impl CargoError for PackageIdError {
- fn description(&self) -> String {
- match *self {
+impl Error for PackageIdError {
+ fn description(&self) -> &str { "failed to parse package id" }
+ fn detail(&self) -> Option<String> {
+ Some(match *self {
PackageIdError::InvalidVersion(ref v) => {
format!("invalid version: {}", *v)
}
PackageIdError::InvalidNamespace(ref ns) => {
format!("invalid namespace: {}", *ns)
}
- }
+ })
}
+}
+
+impl CargoError for PackageIdError {
fn is_human(&self) -> bool { true }
}
+impl FromError<PackageIdError> for Box<CargoError> {
+ fn from_error(t: PackageIdError) -> Box<CargoError> { box t }
+}
+
#[deriving(PartialEq, Hash, Clone, RustcEncodable)]
pub struct Metadata {
pub metadata: String,
use url::{mod, Url, UrlParser};
use core::PackageId;
-use util::{CargoResult, ToUrl, Require, human, ToSemver};
+use util::{CargoResult, ToUrl, human, ToSemver, ChainError};
#[deriving(Clone, PartialEq, Eq)]
pub struct PackageIdSpec {
}
let frag = url.fragment.take();
let (name, version) = {
- let path = try!(url.path().require(|| {
+ let path = try!(url.path().chain_error(|| {
human(format!("pkgid urls must have a path: {}", url))
}));
- let path_name = try!(path.last().require(|| {
+ let path_name = try!(path.last().chain_error(|| {
human(format!("pkgid urls must have at least one path \
component: {}", url))
}));
}
fn load(&mut self, source_id: &SourceId, kind: Kind) -> CargoResult<()> {
- (|| {
+ (|:| {
let mut source = source_id.load(self.config);
// Ensure the source has fetched all necessary remote data.
impl<E, D: Decoder<E>> Decodable<D, E> for EncodablePackageId {
fn decode(d: &mut D) -> Result<EncodablePackageId, E> {
- let string: String = raw_try!(Decodable::decode(d));
+ let string: String = try!(Decodable::decode(d));
let regex = Regex::new(r"^([^ ]+) ([^ ]+)(?: \(([^\)]+)\))?$").unwrap();
let captures = regex.captures(string.as_slice())
.expect("invalid serialized PackageId");
extern crate registry;
use std::os;
-use std::error;
+use std::error::Error;
use std::io::stdio::{stdout_raw, stderr_raw};
use std::io::{mod, stdout, stderr};
use rustc_serialize::{Decoder, Encoder, Decodable, Encodable};
pub use super::util;
}
-#[macro_export]
-macro_rules! try {
- ($expr:expr) => ({
- use std::error::FromError;
- match $expr.map_err(FromError::from_error) {
- Ok(val) => val,
- Err(err) => return Err(err)
- }
- })
-}
-
-macro_rules! raw_try {
- ($expr:expr) => ({
- match $expr {
- Ok(val) => val,
- Err(err) => return Err(err)
- }
- })
-}
-
pub mod core;
pub mod ops;
pub mod sources;
std::os::set_exit_status(exit_code as int);
}
-fn handle_cause(err: &CargoError, shell: &mut MultiShell) {
- let _ = shell.err().say("\nCaused by:", BLACK);
- let _ = shell.err().say(format!(" {}", err.description()), BLACK);
+fn handle_cause(mut err: &Error, shell: &mut MultiShell) {
+ loop {
+ let _ = shell.err().say("\nCaused by:", BLACK);
+ let _ = shell.err().say(format!(" {}", err.description()), BLACK);
- if let Some(e) = err.cause() {
- handle_cause(e, shell)
+ match err.cause() {
+ Some(e) => err = e,
+ None => break,
+ }
}
}
fn flags_from_args<'a, T>(usage: &str, args: &[String],
options_first: bool) -> CliResult<T>
where T: Decodable<docopt::Decoder, docopt::Error> {
+ struct CargoDocoptError { err: docopt::Error }
+ impl Error for CargoDocoptError {
+ fn description(&self) -> &str {
+ match self.err {
+ docopt::Error::WithProgramUsage(..) => "",
+ ref e if e.fatal() => self.err.description(),
+ _ => "",
+ }
+ }
+
+ fn detail(&self) -> Option<String> {
+ match self.err {
+ docopt::Error::WithProgramUsage(_, ref usage) => {
+ Some(usage.clone())
+ }
+ ref e if e.fatal() => None,
+ ref e => Some(e.to_string())
+ }
+ }
+ }
+ impl CargoError for CargoDocoptError {
+ fn is_human(&self) -> bool { true }
+ }
+
let docopt = Docopt::new(usage).unwrap()
.options_first(options_first)
.argv(args.iter().map(|s| s.as_slice()))
.version(Some(version()));
docopt.decode().map_err(|e| {
let code = if e.fatal() {1} else {0};
- CliError::from_error(e, code)
+ CliError::from_error(CargoDocoptError { err: e }, code)
})
}
use ops::{mod, BuildOutput};
use sources::{PathSource};
use util::config::{Config, ConfigValue};
-use util::{CargoResult, Wrap, config, internal, human, ChainError, profile};
+use util::{CargoResult, config, internal, human, ChainError, profile};
/// Contains informations about how a package should be compiled.
pub struct CompileOptions<'a> {
let req: Vec<PackageId> = resolved_with_overrides.iter().map(|r| {
r.clone()
}).collect();
- let packages = try!(registry.get(req.as_slice()).wrap({
+ let packages = try!(registry.get(req.as_slice()).chain_error(|| {
human("Unable to get packages from source")
}));
use core::source::{Source, SourceId};
use core::{Package, MultiShell};
use sources::PathSource;
-use util::{CargoResult, human, internal, ChainError, Require};
+use util::{CargoResult, human, internal, ChainError};
use ops;
struct Bomb { path: Option<Path> }
for file in try!(src.list_files(pkg)).iter() {
if file == dst { continue }
let relative = file.path_relative_from(&root).unwrap();
- let relative = try!(relative.as_str().require(|| {
+ let relative = try!(relative.as_str().chain_error(|| {
human(format!("non-utf8 path in source directory: {}",
relative.display()))
}));
use std::os;
use ops;
-use util::{CargoResult, human, process, ProcessError, Require};
+use util::{CargoResult, human, process, ProcessError, ChainError};
use core::manifest::TargetKind;
use core::source::Source;
use sources::PathSource;
matches_kind && matches_name && a.get_profile().get_env() == env &&
!a.get_profile().is_custom_build()
});
- let bin = try!(bins.next().require(|| {
+ let bin = try!(bins.next().chain_error(|| {
human("a bin target must be available for `cargo run`")
}));
match bins.next() {
use std::sync::Mutex;
use core::{Package, Target, PackageId, PackageSet};
-use util::{CargoResult, CargoError, human};
+use util::{CargoResult, human, Human};
use util::{internal, ChainError};
use super::job::Work;
// And now finally, run the build command itself!
desc_tx.send_opt(p.to_string()).ok();
let output = try!(p.exec_with_output().map_err(|mut e| {
- e.msg = format!("Failed to run custom build command for `{}`\n{}",
- pkg_name, e.msg);
- e.concrete().mark_human()
+ e.desc = format!("failed to run custom build command for `{}`\n{}",
+ pkg_name, e.desc);
+ Human(e)
}));
// After the build command has finished running, we need to be sure to
// This is also the location where we provide feedback into the build
// state informing what variables were discovered via our script as
// well.
- let output = raw_try!(str::from_utf8(output.output.as_slice()).map_err(|_| {
+ let output = try!(str::from_utf8(output.output.as_slice()).chain_error(|| {
human("build script output was not valid utf-8")
}));
let parsed_output = try!(BuildOutput::parse(output, pkg_name.as_slice()));
use core::{Package, Target};
use util;
-use util::{CargoResult, Fresh, Dirty, Freshness, internal, Require, profile};
+use util::{CargoResult, Fresh, Dirty, Freshness, internal, profile, ChainError};
use super::Kind;
use super::job::Work;
};
let line = line.as_slice();
let mtime = try!(fs::stat(dep_info)).modified;
- let pos = try!(line.find_str(": ").require(|| {
+ let pos = try!(line.find_str(": ").chain_error(|| {
internal(format!("dep-info not in an understood format: {}",
dep_info.display()))
}));
use std::io::fs::PathExtensions;
use core::{SourceMap, Package, PackageId, PackageSet, Target, Resolve};
-use util::{mod, CargoResult, ProcessBuilder, CargoError, human, caused_human};
-use util::{Require, Config, internal, ChainError, Fresh, profile, join_paths};
+use util::{mod, CargoResult, ProcessBuilder, human, caused_human};
+use util::{Config, internal, ChainError, Fresh, profile, join_paths, Human};
use self::job::{Job, Work};
use self::job_queue::{JobQueue, Stage};
let triple = output.as_slice().lines().filter(|l| {
l.starts_with("host: ")
}).map(|l| l.slice_from(6)).next();
- let triple = try!(triple.require(|| {
+ let triple = try!(triple.chain_error(|| {
internal("rustc -v didn't have a line for `host:`")
}));
triple.to_string()
let triple = output.as_slice().lines().filter(|l| {
l.starts_with("host: ")
}).map(|l| l.slice_from(6)).next();
- let triple = try!(triple.require(|| {
+ let triple = try!(triple.chain_error(|| {
internal("rustc -v didn't have a line for `host:`")
}));
triple.to_string()
}))
}
try!(p.exec_with_output().map(|_| ()).map_err(|mut e| {
- e.msg = format!("Failed to run custom build command for `{}`\n{}",
- pkg, e.msg);
- e.concrete().mark_human()
+ e.desc = format!("Failed to run custom build command for `{}`\n{}",
+ pkg, e.desc);
+ Human(e)
}));
Ok(())
}))
}))
} else {
try!(rustdoc.exec_with_output().and(Ok(())).map_err(|err| {
- match err.output() {
- Some(output) => {
- caused_human(format!("Could not document `{}`.\n{}",
- name, output), err)
+ match err.exit {
+ Some(..) => {
+ caused_human(format!("Could not document `{}`.",
+ name), err)
}
None => {
caused_human("Failed to run rustdoc", err)
use git2;
use core::GitReference;
-use util::{CargoResult, ChainError, human, ToUrl, internal, Require};
+use util::{CargoResult, ChainError, human, ToUrl, internal};
#[deriving(PartialEq, Clone)]
#[allow(missing_copy_implementations)]
pub fn rev_for(&self, reference: &GitReference) -> CargoResult<GitRevision> {
let id = match *reference {
GitReference::Tag(ref s) => {
- try!((|| {
+ try!((|:| {
let refname = format!("refs/tags/{}", s);
let id = try!(self.repo.refname_to_id(refname.as_slice()));
let tag = try!(self.repo.find_tag(id));
}))
}
GitReference::Branch(ref s) => {
- try!((|| {
+ try!((|:| {
let b = try!(self.repo.find_branch(s.as_slice(),
git2::BranchType::Local));
- b.get().target().require(|| {
+ b.get().target().chain_error(|| {
human(format!("branch `{}` did not have a target", s))
})
}).chain_error(|| {
for mut child in try!(repo.submodules()).into_iter() {
try!(child.init(false));
- let url = try!(child.url().require(|| {
+ let url = try!(child.url().chain_error(|| {
internal("non-utf8 url for submodule")
}));
use core::dependency::{Dependency, Kind};
use sources::{PathSource, git};
use util::{CargoResult, Config, internal, ChainError, ToUrl, human};
-use util::{hex, Require, Sha256};
+use util::{hex, Sha256};
use ops;
static DEFAULT: &'static str = "https://github.com/rust-lang/crates.io-index";
// Verify what we just downloaded
let expected = self.hashes.get(&(pkg.get_name().to_string(),
pkg.get_version().to_string()));
- let expected = try!(expected.require(|| {
+ let expected = try!(expected.chain_error(|| {
internal(format!("no hash listed for {}", pkg))
}));
let actual = {
use toml;
use core::MultiShell;
use ops;
-use util::{CargoResult, ChainError, Require, internal, human};
+use util::{CargoResult, ChainError, internal, human};
use util::toml as cargo_toml;
let (rustc_version, rustc_host) = try!(ops::rustc_version());
Ok(Config {
- home_path: try!(homedir().require(|| {
+ home_path: try!(homedir().chain_error(|| {
human("Cargo couldn't find your home directory. \
This probably means that $HOME was not set.")
})),
}
toml::Value::Table(val) => {
Ok(CV::Table(try!(val.into_iter().map(|(key, value)| {
- let value = raw_try!(CV::from_toml(path, value));
+ let value = try!(CV::from_toml(path, value));
Ok((key, value))
}).collect::<CargoResult<_>>())))
}
// Once we're done, also be sure to walk the home directory even if it's not
// in our history to be sure we pick up that standard location for
// information.
- let home = try!(homedir().require(|| {
+ let home = try!(homedir().chain_error(|| {
human("Cargo couldn't find your home directory. \
This probably means that $HOME was not set.")
}));
fn extract_config(mut file: File, key: &str) -> CargoResult<ConfigValue> {
let contents = try!(file.read_to_string());
let mut toml = try!(cargo_toml::parse(contents.as_slice(), file.path()));
- let val = try!(toml.remove(&key.to_string()).require(|| internal("")));
+ let val = try!(toml.remove(&key.to_string()).chain_error(|| internal("")));
CV::from_toml(file.path(), val)
}
-use std::io::process::{ProcessOutput, ProcessExit, ExitStatus, ExitSignal};
+use std::error::{FromError, Error};
+use std::fmt::{mod, Show};
use std::io::IoError;
-use std::fmt::{mod, Show, Formatter};
+use std::io::process::{ProcessOutput, ProcessExit, ExitStatus, ExitSignal};
use std::str;
-use rustc_serialize::json;
+
use semver;
-use std::error::FromError;
+use rustc_serialize::json;
use curl;
-use docopt;
use toml::Error as TomlError;
use url;
use git2;
-pub trait CargoError: Send {
- fn description(&self) -> String;
- fn detail(&self) -> Option<String> { None }
- fn cause(&self) -> Option<&CargoError> { None }
- fn is_human(&self) -> bool { false }
+pub type CargoResult<T> = Result<T, Box<CargoError>>;
- fn concrete(&self) -> ConcreteCargoError {
- ConcreteCargoError {
- description: self.description(),
- detail: self.detail(),
- cause: self.cause().map(|c| box c.concrete() as Box<CargoError>),
- is_human: self.is_human()
- }
- }
+// =============================================================================
+// CargoError trait
+
+pub trait CargoError: Error {
+ fn is_human(&self) -> bool { false }
}
impl Show for Box<CargoError> {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{}", self.description()));
Ok(())
}
}
-impl CargoError for Box<CargoError> {
- fn description(&self) -> String { (**self).description() }
+impl Error for Box<CargoError> {
+ fn description(&self) -> &str { (**self).description() }
fn detail(&self) -> Option<String> { (**self).detail() }
- fn cause(&self) -> Option<&CargoError> { (**self).cause() }
- fn is_human(&self) -> bool { (**self).is_human() }
+ fn cause(&self) -> Option<&Error> { (**self).cause() }
}
-impl CargoError for semver::ReqParseError {
- fn description(&self) -> String {
- self.to_string()
- }
+impl CargoError for Box<CargoError> {
+ fn is_human(&self) -> bool { (**self).is_human() }
}
-pub type CargoResult<T> = Result<T, Box<CargoError>>;
-
-pub trait BoxError<T> {
- fn box_error(self) -> CargoResult<T>;
-}
+// =============================================================================
+// Chaining errors
pub trait ChainError<T> {
- fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T> ;
+ fn chain_error<E, F>(self, callback: F) -> CargoResult<T>
+ where E: CargoError, F: FnOnce() -> E;
}
-impl<'a, T> ChainError<T> for ||:'a -> CargoResult<T> {
- fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T> {
- self().map_err(|err| callback().concrete().with_cause(err))
- }
+struct ChainedError<E> {
+ error: E,
+ cause: Box<Error>,
}
-impl<T, E: CargoError> BoxError<T> for Result<T, E> {
- fn box_error(self) -> CargoResult<T> {
- self.map_err(|err| box err as Box<CargoError>)
+impl<'a, T, F> ChainError<T> for F where F: FnOnce() -> CargoResult<T> {
+ fn chain_error<E, C>(self, callback: C) -> CargoResult<T>
+ where E: CargoError, C: FnOnce() -> E {
+ self().chain_error(callback)
}
}
-impl<T, E: CargoError> ChainError<T> for Result<T, E> {
- fn chain_error<E: CargoError>(self, callback: || -> E) -> CargoResult<T> {
- self.map_err(|err| callback().concrete().with_cause(err))
+impl<T, E: Error> ChainError<T> for Result<T, E> {
+ fn chain_error<E2, C>(self, callback: C) -> CargoResult<T>
+ where E2: CargoError, C: FnOnce() -> E2 {
+ self.map_err(move |err| {
+ box ChainedError {
+ error: callback(),
+ cause: box err,
+ } as Box<CargoError>
+ })
}
}
-impl CargoError for IoError {
- fn description(&self) -> String { self.to_string() }
-}
-
-impl CargoError for TomlError {
- fn description(&self) -> String { self.to_string() }
-}
-
-impl CargoError for fmt::Error {
- fn description(&self) -> String {
- "formatting failed".to_string()
+impl<T> ChainError<T> for Option<T> {
+ fn chain_error<E, C>(self, callback: C) -> CargoResult<T>
+ where E: CargoError, C: FnOnce() -> E {
+ match self {
+ Some(t) => Ok(t),
+ None => Err(box callback() as Box<CargoError>),
+ }
}
}
-impl CargoError for curl::ErrCode {
- fn description(&self) -> String { self.to_string() }
+impl<E: Error> Error for ChainedError<E> {
+ fn description(&self) -> &str { self.error.description() }
+ fn detail(&self) -> Option<String> { self.error.detail() }
+ fn cause(&self) -> Option<&Error> { Some(&*self.cause) }
}
-impl CargoError for json::DecoderError {
- fn description(&self) -> String { self.to_string() }
+impl<E: CargoError> CargoError for ChainedError<E> {
+ fn is_human(&self) -> bool { self.error.is_human() }
}
+// =============================================================================
+// Process errors
+
pub struct ProcessError {
- pub msg: String,
+ pub desc: String,
pub exit: Option<ProcessExit>,
pub output: Option<ProcessOutput>,
- pub detail: Option<String>,
- pub cause: Option<Box<CargoError>>
+ cause: Option<IoError>,
}
-impl Show for ProcessError {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- let exit = match self.exit {
- Some(ExitStatus(i)) | Some(ExitSignal(i)) => i.to_string(),
- None => "never executed".to_string()
- };
- try!(write!(f, "{} (status={})", self.msg, exit));
- if let Some(out) = self.output() {
- try!(write!(f, "{}", out));
- }
- Ok(())
+impl Error for ProcessError {
+ fn description(&self) -> &str { self.desc.as_slice() }
+ fn detail(&self) -> Option<String> { None }
+ fn cause(&self) -> Option<&Error> {
+ self.cause.as_ref().map(|s| s as &Error)
}
}
-impl ProcessError {
- pub fn output(&self) -> Option<String> {
- match self.output {
- Some(ref out) => {
- let mut string = String::new();
- match str::from_utf8(out.output.as_slice()) {
- Ok(s) if s.trim().len() > 0 => {
- string.push_str("\n--- stdout\n");
- string.push_str(s);
- }
- Ok(..) | Err(..) => {}
- }
- match str::from_utf8(out.error.as_slice()) {
- Ok(s) if s.trim().len() > 0 => {
- string.push_str("\n--- stderr\n");
- string.push_str(s);
- }
- Ok(..) | Err(..) => {}
- }
- Some(string)
- },
- None => None
- }
+impl fmt::Show for ProcessError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.desc.fmt(f)
}
}
-impl CargoError for ProcessError {
- fn description(&self) -> String { self.to_string() }
+// =============================================================================
+// Concrete errors
- fn detail(&self) -> Option<String> {
- self.detail.clone()
- }
-
- fn cause(&self) -> Option<&CargoError> {
- self.cause.as_ref().map(|c| { let err: &CargoError = &**c; err })
- }
-}
-
-pub struct ConcreteCargoError {
+struct ConcreteCargoError {
description: String,
detail: Option<String>,
- cause: Option<Box<CargoError>>,
- is_human: bool
+ cause: Option<Box<Error>>,
+ is_human: bool,
}
-impl ConcreteCargoError {
- pub fn with_cause<E: CargoError>(mut self, err: E) -> Box<CargoError> {
- self.cause = Some(box err as Box<CargoError>);
- box self as Box<CargoError>
- }
-
- pub fn mark_human(mut self) -> Box<CargoError> {
- self.is_human = true;
- box self as Box<CargoError>
+impl fmt::Show for ConcreteCargoError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.description)
}
}
-impl Show for ConcreteCargoError {
- fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- write!(f, "{}", self.description)
+impl Error for ConcreteCargoError {
+ fn description(&self) -> &str { self.description.as_slice() }
+ fn detail(&self) -> Option<String> { self.detail.clone() }
+ fn cause(&self) -> Option<&Error> {
+ self.cause.as_ref().map(|c| &**c)
}
}
impl CargoError for ConcreteCargoError {
- fn description(&self) -> String {
- self.description.clone()
+ fn is_human(&self) -> bool {
+ self.is_human
}
+}
- fn detail(&self) -> Option<String> {
- self.detail.clone()
- }
+// =============================================================================
+// Human errors
- fn cause(&self) -> Option<&CargoError> {
- self.cause.as_ref().map(|c| { let err: &CargoError = &**c; err })
- }
+pub struct Human<E>(pub E);
- fn is_human(&self) -> bool {
- self.is_human
- }
+impl<E: Error> Error for Human<E> {
+ fn description(&self) -> &str { self.0.description() }
+ fn detail(&self) -> Option<String> { self.0.detail() }
+ fn cause(&self) -> Option<&Error> { self.0.cause() }
}
+impl<E: Error> CargoError for Human<E> {
+ fn is_human(&self) -> bool { true }
+}
+
+// =============================================================================
+// CLI errors
+
pub type CliResult<T> = Result<T, CliError>;
#[deriving(Show)]
pub exit_code: uint
}
-impl CargoError for CliError {
- fn description(&self) -> String {
- self.error.to_string()
- }
-}
-
-impl CargoError for docopt::Error {
- fn description(&self) -> String {
- match *self {
- docopt::Error::WithProgramUsage(ref other, _) => other.description(),
- ref e if e.fatal() => self.to_string(),
- _ => "".to_string(),
- }
- }
-
- fn detail(&self) -> Option<String> {
- match *self {
- docopt::Error::WithProgramUsage(_, ref usage) => Some(usage.clone()),
- ref e if e.fatal() => None,
- ref e => Some(e.to_string()),
- }
- }
-
- fn is_human(&self) -> bool { true }
-}
-
-impl CargoError for url::ParseError {
- fn description(&self) -> String { self.to_string() }
-}
-
-impl CargoError for git2::Error {
- fn description(&self) -> String { self.to_string() }
+impl Error for CliError {
+ fn description(&self) -> &str { self.error.description() }
+ fn detail(&self) -> Option<String> { self.error.detail() }
+ fn cause(&self) -> Option<&Error> { self.error.cause() }
}
impl CliError {
}
}
+// =============================================================================
+// various impls
+
+macro_rules! from_error {
+ ($($p:ty,)*) => (
+ $(impl FromError<$p> for Box<CargoError> {
+ fn from_error(t: $p) -> Box<CargoError> { box t }
+ })*
+ )
+}
+
+from_error! {
+ semver::ReqParseError,
+ IoError,
+ ProcessError,
+ git2::Error,
+ json::DecoderError,
+ curl::ErrCode,
+ CliError,
+ TomlError,
+ url::ParseError,
+}
+
+impl<E: Error> FromError<Human<E>> for Box<CargoError> {
+ fn from_error(t: Human<E>) -> Box<CargoError> { box t }
+}
+
+impl CargoError for semver::ReqParseError {}
+impl CargoError for IoError {}
+impl CargoError for git2::Error {}
+impl CargoError for json::DecoderError {}
+impl CargoError for curl::ErrCode {}
+impl CargoError for ProcessError {}
+impl CargoError for CliError {}
+impl CargoError for TomlError {}
+impl CargoError for url::ParseError {}
+
+// =============================================================================
+// Construction helpers
+
pub fn process_error<S: Str>(msg: S,
cause: Option<IoError>,
status: Option<&ProcessExit>,
output: Option<&ProcessOutput>) -> ProcessError {
+ let exit = match status {
+ Some(&ExitStatus(i)) | Some(&ExitSignal(i)) => i.to_string(),
+ None => "never executed".to_string(),
+ };
+ let mut desc = format!("{} (status={})", msg.as_slice(), exit);
+
+ if let Some(out) = output {
+ match str::from_utf8(out.output.as_slice()) {
+ Ok(s) if s.trim().len() > 0 => {
+ desc.push_str("\n--- stdout\n");
+ desc.push_str(s);
+ }
+ Ok(..) | Err(..) => {}
+ }
+ match str::from_utf8(out.error.as_slice()) {
+ Ok(s) if s.trim().len() > 0 => {
+ desc.push_str("\n--- stderr\n");
+ desc.push_str(s);
+ }
+ Ok(..) | Err(..) => {}
+ }
+ }
+
ProcessError {
- msg: msg.as_slice().to_string(),
- exit: status.map(|o| o.clone()),
- output: output.map(|o| o.clone()),
- detail: None,
- cause: cause.map(|c| box c as Box<CargoError>)
+ desc: desc,
+ exit: status.map(|a| a.clone()),
+ output: output.map(|a| a.clone()),
+ cause: cause,
}
}
detail: Some(detail.as_slice().to_string()),
cause: None,
is_human: false
- } as Box<CargoError>
+ }
}
pub fn internal<S: Show>(error: S) -> Box<CargoError> {
detail: None,
cause: None,
is_human: false
- } as Box<CargoError>
+ }
}
pub fn human<S: Show>(error: S) -> Box<CargoError> {
detail: None,
cause: None,
is_human: true
- } as Box<CargoError>
+ }
}
-pub fn caused_human<S: Show, E: CargoError>(error: S, cause: E) -> Box<CargoError> {
+pub fn caused_human<S: Show, E: Error>(error: S, cause: E) -> Box<CargoError> {
box ConcreteCargoError {
description: error.to_string(),
detail: None,
- cause: Some(box cause as Box<CargoError>),
+ cause: Some(box cause as Box<Error>),
is_human: true
- } as Box<CargoError>
+ }
}
pub use self::config::Config;
pub use self::process_builder::{process, ProcessBuilder};
-pub use self::result::{Wrap, Require};
-pub use self::errors::{CargoResult, CargoError, BoxError, ChainError, CliResult};
+pub use self::errors::{CargoResult, CargoError, ChainError, CliResult};
pub use self::errors::{CliError, ProcessError};
-pub use self::errors::{process_error, internal_error, internal, human, caused_human};
+pub use self::errors::{process_error, internal_error, internal, human};
+pub use self::errors::{Human, caused_human};
pub use self::paths::{realpath, join_paths};
pub use self::lev_distance::{lev_distance};
pub use self::hex::{to_hex, short_hash};
pub mod paths;
pub mod process_builder;
pub mod profile;
-pub mod result;
pub mod to_semver;
pub mod to_url;
pub mod toml;
let output = try!(command.output().map_err(|e| {
process_error(format!("Could not execute process `{}`",
- self.debug_string()),
+ self.debug_string()),
Some(e), None, None)
}));
+++ /dev/null
-use util::errors::{CargoResult, CargoError};
-
-pub trait Wrap {
- fn wrap<E: CargoError>(self, error: E) -> Self;
-}
-
-impl<T> Wrap for Result<T, Box<CargoError>> {
- fn wrap<E: CargoError>(self, error: E) -> CargoResult<T> {
- match self {
- Ok(x) => Ok(x),
- Err(e) => Err(error.concrete().with_cause(e))
- }
- }
-}
-
-pub trait Require<T> {
- fn require<E: CargoError>(self, err: || -> E) -> CargoResult<T>;
-}
-
-impl<T> Require<T> for Option<T> {
- fn require<E: CargoError>(self, err: || -> E) -> CargoResult<T> {
- match self {
- Some(x) => Ok(x),
- None => Err(box err().concrete() as Box<CargoError>)
- }
- }
-}
use core::dependency::Kind;
use core::manifest::{LibKind, Profile, ManifestMetadata};
use core::package_id::Metadata;
-use util::{CargoResult, Require, human, ToUrl, ToSemver};
+use util::{CargoResult, human, ToUrl, ToSemver, ChainError};
/// Representation of the projects file layout.
///
Some(path) => path,
None => manifest,
};
- let contents = raw_try!(str::from_utf8(contents).map_err(|_| {
+ let contents = try!(str::from_utf8(contents).chain_error(|| {
human(format!("{} is not valid UTF-8", manifest.display()))
}));
let root = try!(parse(contents, &manifest));
impl<E, D: Decoder<E>> Decodable<D, E> for TomlVersion {
fn decode(d: &mut D) -> Result<TomlVersion, E> {
- let s = raw_try!(d.read_str());
+ let s = try!(d.read_str());
match s.as_slice().to_semver() {
Ok(s) => Ok(TomlVersion { version: s }),
Err(e) => Err(d.error(e.as_slice())),
let mut nested_paths = vec!();
let project = self.project.as_ref().or_else(|| self.package.as_ref());
- let project = try!(project.require(|| {
+ let project = try!(project.chain_error(|| {
human("No `package` or `project` section found.")
}));
+use std::error::Error;
use std::fmt::{mod, Show};
use std::io::fs::{mod, PathExtensions};
use std::io::process::{ProcessOutput};
use std::os;
use std::path::{Path,BytesContainer};
use std::str::{mod, Str};
-use std::vec::Vec;
+
use url::Url;
use hamcrest as ham;
use cargo::util::{process,ProcessBuilder};
}
Err(e) => {
let mut s = format!("could not exec process {}: {}", process, e);
- match e.cause {
+ match e.cause() {
Some(cause) => s.push_str(format!("\ncaused by: {}",
- cause).as_slice()),
+ cause.description()).as_slice()),
None => {}
}
Err(s)
ShellWrites { expected: string.to_string() }
}
-pub trait ResultTest<T,E> {
- fn assert(self) -> T;
-}
-
-impl<T,E: Show> ResultTest<T,E> for Result<T,E> {
- fn assert(self) -> T {
- match self {
- Ok(val) => val,
- Err(err) => panic!("Result was error: {}", err)
- }
- }
-}
-
-impl<T> ResultTest<T,()> for Option<T> {
- fn assert(self) -> T {
- match self {
- Some(val) => val,
- None => panic!("Option was None")
- }
- }
-}
-
pub trait Tap {
fn tap(mut self, callback: |&mut Self|) -> Self;
}
use tar::Archive;
use url::Url;
-use support::{ResultTest, project};
+use support::project;
use support::paths;
use support::git::repo;
use cargo::util::Sha256;
pub fn init() {
let config = paths::home().join(".cargo/config");
- fs::mkdir_recursive(&config.dir_path(), io::USER_DIR).assert();
+ fs::mkdir_recursive(&config.dir_path(), io::USER_DIR).unwrap();
File::create(&config).write_str(format!(r#"
[registry]
index = "{reg}"
token = "api-token"
- "#, reg = registry()).as_slice()).assert();
+ "#, reg = registry()).as_slice()).unwrap();
// Init a new registry
repo(®istry_path())
p.build();
let dst = mock_archive_dst(name, version);
- fs::mkdir_recursive(&dst.dir_path(), io::USER_DIR).assert();
+ fs::mkdir_recursive(&dst.dir_path(), io::USER_DIR).unwrap();
let f = File::create(&dst).unwrap();
let a = Archive::new(GzEncoder::new(f, Default));
a.append(format!("{}-{}/Cargo.toml", name, version).as_slice(),
use cargo::util::process;
use support::paths;
-use support::{execs, project, cargo_dir, mkdir_recursive, ProjectBuilder, ResultTest};
+use support::{execs, project, cargo_dir, mkdir_recursive, ProjectBuilder};
use hamcrest::{assert_that};
fn setup() {
/// TODO: move this to `ProjectBuilder` if other cases using this emerge.
fn fake_executable(proj: ProjectBuilder, dir: &Path, name: &str) -> ProjectBuilder {
let path = proj.root().join(dir).join(format!("{}{}", name, os::consts::EXE_SUFFIX));
- mkdir_recursive(&Path::new(path.dirname())).assert();
- fs::File::create(&path).assert();
- let io::FileStat{perm, ..} = fs::stat(&path).assert();
- fs::chmod(&path, io::OTHER_EXECUTE | perm).assert();
+ mkdir_recursive(&Path::new(path.dirname())).unwrap();
+ fs::File::create(&path).unwrap();
+ let io::FileStat{perm, ..} = fs::stat(&path).unwrap();
+ fs::chmod(&path, io::OTHER_EXECUTE | perm).unwrap();
proj
}
path.push(proj.root().join("path-test"));
let path = os::join_paths(path.as_slice()).unwrap();
let output = pr.arg("-v").arg("--list").env("PATH", Some(path.as_slice()));
- let output = output.exec_with_output().assert();
- let output = str::from_utf8(output.output.as_slice()).assert();
+ let output = output.exec_with_output().unwrap();
+ let output = str::from_utf8(output.output.as_slice()).unwrap();
assert!(output.contains("\n 1\n"), "missing 1: {}", output);
});
test!(override_cargo_home {
let root = paths::root();
let my_home = root.join("my_home");
- fs::mkdir(&my_home, USER_RWX).assert();
- fs::mkdir(&my_home.join(".cargo"), USER_RWX).assert();
+ fs::mkdir(&my_home, USER_RWX).unwrap();
+ fs::mkdir(&my_home.join(".cargo"), USER_RWX).unwrap();
File::create(&my_home.join(".cargo/config")).write_str(r#"
[cargo-new]
name = "foo"
email = "bar"
git = false
- "#).assert();
+ "#).unwrap();
assert_that(process(cargo_dir().join("cargo")).unwrap()
.arg("new").arg("foo")
execs().with_status(0));
let toml = paths::root().join("foo/Cargo.toml");
- let toml = File::open(&toml).read_to_string().assert();
+ let toml = File::open(&toml).read_to_string().unwrap();
assert!(toml.as_slice().contains(r#"authors = ["foo <bar>"]"#));
});
use std::str;
use support::{project, execs, basic_bin_manifest, basic_lib_manifest};
-use support::{COMPILING, cargo_dir, ResultTest, FRESH, RUNNING};
+use support::{COMPILING, cargo_dir, FRESH, RUNNING};
use support::paths::PathExt;
use hamcrest::{assert_that, existing_file};
use cargo::util::process;
#[bench] fn bench_bench(_b: &mut test::Bencher) { foo::foo() }
"#);
- let output = p.cargo_process("bench").exec_with_output().assert();
- let output = str::from_utf8(output.output.as_slice()).assert();
+ let output = p.cargo_process("bench").exec_with_output().unwrap();
+ let output = str::from_utf8(output.output.as_slice()).unwrap();
assert!(output.contains("test bin_bench"), "bin_bench missing\n{}", output);
assert!(output.contains("test lib_bench"), "lib_bench missing\n{}", output);
assert!(output.contains("test bench_bench"), "bench_bench missing\n{}", output);
}
"#);
- let output = p.cargo_process("bench").exec_with_output().assert();
- let output = str::from_utf8(output.output.as_slice()).assert();
+ let output = p.cargo_process("bench").exec_with_output().unwrap();
+ let output = str::from_utf8(output.output.as_slice()).unwrap();
assert!(output.contains("main_bench ... bench: 0 ns/iter (+/- 0)"),
"no main_bench\n{}",
output);
",
compiling = COMPILING, running = RUNNING,
dir = p.url()).as_slice()));
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("bench").arg("-v"),
execs().with_status(0)
.with_stdout(format!("\
use std::thread::Thread;
use git2;
-use support::{project, execs, ResultTest, UPDATING};
+use support::{project, execs, UPDATING};
use support::paths;
use hamcrest::assert_that;
// Test that HTTP auth is offered from `credential.helper`
test!(http_auth_offered {
- let mut listener = TcpListener::bind("127.0.0.1:0").assert();
- let addr = listener.socket_name().assert();
+ let mut listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = listener.socket_name().unwrap();
let mut a = listener.listen().unwrap();
let a2 = a.clone();
let _c = Closer { a: a2 };
failed to clone into: [..]
Caused by:
- [12] [..] status code: 401
+ [..] status code: 401
",
addr = addr)));
// Boy, sure would be nice to have a TLS implementation in rust!
test!(https_something_happens {
- let mut listener = TcpListener::bind("127.0.0.1:0").assert();
- let addr = listener.socket_name().assert();
+ let mut listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = listener.socket_name().unwrap();
let mut a = listener.listen().unwrap();
let a2 = a.clone();
let _c = Closer { a: a2 };
failed to clone into: [..]
Caused by:
- [[..]] {errmsg}
+ {errmsg}
",
addr = addr,
errmsg = if cfg!(windows) {
// Boy, sure would be nice to have an SSH implementation in rust!
test!(ssh_something_happens {
- let mut listener = TcpListener::bind("127.0.0.1:0").assert();
- let addr = listener.socket_name().assert();
+ let mut listener = TcpListener::bind("127.0.0.1:0").unwrap();
+ let addr = listener.socket_name().unwrap();
let mut a = listener.listen().unwrap();
let a2 = a.clone();
let _c = Closer { a: a2 };
failed to clone into: [..]
Caused by:
- [23] Failed to start SSH session: Failed getting banner
+ Failed to start SSH session: Failed getting banner
",
addr = addr)));
t.join().ok().unwrap();
use std::os;
use std::path;
-use support::{ResultTest, project, execs, main_file, basic_bin_manifest};
+use support::{project, execs, main_file, basic_bin_manifest};
use support::{COMPILING, RUNNING, cargo_dir, ProjectBuilder};
use hamcrest::{assert_that, existing_file};
use support::paths::PathExt;
p.cargo_process("build")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("foo"), existing_file());
p.cargo_process("build")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("foo"), existing_file());
p.cargo_process("build")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("foo"), existing_file());
assert_that(p.cargo_process("build"),
execs().with_status(0));
- let files = fs::readdir(&p.root().join("target")).assert();
+ let files = fs::readdir(&p.root().join("target")).unwrap();
let mut files: Vec<String> = files.iter().filter_map(|f| {
match f.filename_str().unwrap() {
"build" | "examples" | "deps" => None,
assert_that(p.cargo_process("build"),
execs().with_status(0));
- let files = fs::readdir(&p.root().join("target")).assert();
+ let files = fs::readdir(&p.root().join("target")).unwrap();
let mut files: Vec<String> = files.iter().filter_map(|f| {
match f.filename_str().unwrap() {
"build" | "examples" | "deps" => None,
"#)
.file("src/lib.rs", "pub fn bar() -> int { 1 }");
foo.build();
- foo.root().move_into_the_past().assert();
+ foo.root().move_into_the_past().unwrap();
assert_that(foo.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0)
// Modify an ignored file and make sure we don't rebuild
println!("second pass");
- File::create(&foo.root().join("src/bar.rs")).assert();
+ File::create(&foo.root().join("src/bar.rs")).unwrap();
assert_that(foo.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0)
.with_stdout(""));
"#, build.bin("builder").display()).as_slice())
.file("src/lib.rs", "pub fn bar() -> int { 1 }");
foo.build();
- foo.root().move_into_the_past().assert();
+ foo.root().move_into_the_past().unwrap();
assert_that(foo.process(cargo_dir().join("cargo")).arg("build")
.env("FIRST", Some("1")),
{compiling} foo v0.0.0 ({url})
", compiling = COMPILING, url = foo.url())));
- File::create(&foo.root().join("src/bar.rs")).assert();
+ File::create(&foo.root().join("src/bar.rs")).unwrap();
assert_that(foo.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0)
.with_stdout(format!("\
"#)
.file("src/my lib.rs", "");
assert_that(foo.cargo_process("build"), execs().with_status(0));
- foo.root().move_into_the_past().assert();
+ foo.root().move_into_the_past().unwrap();
assert_that(foo.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0).with_stdout(""));
});
p.cargo_process("build")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("foo"), existing_file());
p.cargo_process("build")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("foo"), existing_file());
execs());
let lockfile = p.root().join("Cargo.lock");
- let lockfile = File::open(&lockfile).read_to_string().assert();
+ let lockfile = File::open(&lockfile).read_to_string().unwrap();
assert!(lockfile.as_slice().contains("bar"))
});
p.cargo_process("test").arg("--no-run")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("examples/foo"), existing_file());
p.process(cargo_dir().join("cargo")).arg("test").arg("--no-run")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("foo"), existing_file());
assert_that(&p.bin("examples/foo"), existing_file());
",
url = p.url(), compiling = COMPILING, running = RUNNING))
.with_stderr(format!("\
-Failed to run custom build command for `foo v0.5.0 ({})`
+failed to run custom build command for `foo v0.5.0 ({})`
Process didn't exit successfully: `[..]build[..]build-script-build[..]` (status=101)",
p.url())));
});
use std::time::Duration;
use git2;
-use support::{ProjectBuilder, ResultTest, project, execs, main_file};
+use support::{ProjectBuilder, project, execs, main_file};
use support::{cargo_dir, path2url};
use support::{COMPILING, UPDATING, RUNNING};
use support::paths::PathExt;
"hello world"
}
"#)
- }).assert();
+ }).unwrap();
let project = project
.file("Cargo.toml", format!(r#"
"hello world"
}
"#)
- }).assert();
+ }).unwrap();
// Make a new branch based on the current HEAD commit
let repo = git2::Repository::open(&git_project.root()).unwrap();
"hello world"
}
"#)
- }).assert();
+ }).unwrap();
// Make a tag correponding to the current HEAD
let repo = git2::Repository::open(&git_project.root()).unwrap();
"hello world"
}
"#)
- }).assert();
+ }).unwrap();
let p = project("parent")
.file("Cargo.toml", format!(r#"
p.cargo_process("build")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("parent"), existing_file());
"this is dep2"
}
"#)
- }).assert();
+ }).unwrap();
let p = project("parent")
.file("Cargo.toml", format!(r#"
p.cargo_process("build")
.exec_with_output()
- .assert();
+ .unwrap();
assert_that(&p.bin("parent"), existing_file());
authors = []
"#)
.file("src/lib.rs", "pub fn bar() -> int { 1 }")
- }).assert();
+ }).unwrap();
let repo = git2::Repository::open(&bar.root()).unwrap();
let rev1 = repo.revparse_single("HEAD").unwrap().id();
// Commit the changes and make sure we trigger a recompile
File::create(&bar.root().join("src/lib.rs")).write_str(r#"
pub fn bar() -> int { 2 }
- "#).assert();
+ "#).unwrap();
add(&repo);
let rev2 = commit(&repo);
.file("src/bar.rs", r#"
pub fn bar() {}
"#)
- }).assert();
+ }).unwrap();
let p = project("foo")
.file("Cargo.toml", format!(r#"
// Modify a file manually, shouldn't trigger a recompile
File::create(&git_project.root().join("src/bar.rs")).write_str(r#"
pub fn bar() { println!("hello!"); }
- "#).assert();
+ "#).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(""));
println!("compile after commit");
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(""));
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
// Update the dependency and carry on!
assert_that(p.process(cargo_dir().join("cargo")).arg("update"),
.file("src/bar.rs", r#"
pub fn bar() {}
"#)
- }).assert();
+ }).unwrap();
let p = project("foo")
.file("Cargo.toml", r#"
// Modify a file manually, and commit it
File::create(&git_project.root().join("src/bar.rs")).write_str(r#"
pub fn bar() { println!("hello!"); }
- "#).assert();
+ "#).unwrap();
let repo = git2::Repository::open(&git_project.root()).unwrap();
let old_head = repo.head().unwrap().target().unwrap();
add(&repo);
version = "0.5.0"
authors = ["carlhuda@example.com"]
"#)
- }).assert();
+ }).unwrap();
let git_project2 = git_repo("dep2", |project| {
project
.file("lib.rs", "pub fn dep() {}")
- }).assert();
+ }).unwrap();
let repo = git2::Repository::open(&git_project.root()).unwrap();
let url = path2url(git_project2.root()).to_string();
authors = ["carlhuda@example.com"]
"#)
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let git2 = git_repo("dep2", |project| {
project
.file("Cargo.toml", r#"
authors = ["carlhuda@example.com"]
"#)
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let project = project
.file("Cargo.toml", format!(r#"
File::create(&git1.root().join("src/lib.rs")).write_str(r#"
pub fn foo() {}
- "#).assert();
+ "#).unwrap();
let repo = git2::Repository::open(&git1.root()).unwrap();
add(&repo);
commit(&repo);
authors = []
"#)
.file("src/lib.rs", "pub fn bar() -> int { 1 }")
- }).assert();
+ }).unwrap();
// Update the git database in the cache with the current state of the git
// repo
// us pulling it down.
File::create(&bar.root().join("src/lib.rs")).write_str(r#"
pub fn bar() -> int { 1 + 0 }
- "#).assert();
+ "#).unwrap();
let repo = git2::Repository::open(&bar.root()).unwrap();
add(&repo);
commit(&repo);
name = "bar"
version = "0.0.0"
source = 'git+{url}#{hash}'
- "#, url = bar.url(), hash = rev).as_slice()).assert();
+ "#, url = bar.url(), hash = rev).as_slice()).unwrap();
// Now build!
assert_that(foo.process(cargo_dir().join("cargo")).arg("build"),
version = "0.5.0"
authors = ["carlhuda@example.com"]
"#)
- }).assert();
+ }).unwrap();
let git_project2 = git_repo("dep2", |project| {
project
.file("lib.rs", "pub fn dep() -> &'static str { \"project2\" }")
- }).assert();
+ }).unwrap();
let git_project3 = git_repo("dep3", |project| {
project
.file("lib.rs", "pub fn dep() -> &'static str { \"project3\" }")
- }).assert();
+ }).unwrap();
let repo = git2::Repository::open(&git_project.root()).unwrap();
let mut sub = add_submodule(&repo, git_project2.url().to_string().as_slice(),
let mut file = File::create(&git_project.root().join(".gitmodules"));
file.write_str(format!("[submodule \"src\"]\n\tpath = src\n\turl={}",
- git_project3.url()).as_slice()).assert();
+ git_project3.url()).as_slice()).unwrap();
// Sync the submodule and reset it to the new remote.
sub.sync().unwrap();
.file("src/lib.rs", r#"
pub fn gimme() -> &'static str { "zoidberg" }
"#)
- }).assert();
+ }).unwrap();
let p = project("foo")
.file("Cargo.toml", format!(r#"
.file(".gitignore", "
src/bar.rs
")
- }).assert();
- foo.root().move_into_the_past().assert();
+ }).unwrap();
+ foo.root().move_into_the_past().unwrap();
timer::sleep(Duration::milliseconds(1000));
// Modify an ignored file and make sure we don't rebuild
println!("second pass");
- File::create(&foo.root().join("src/bar.rs")).assert();
+ File::create(&foo.root().join("src/bar.rs")).unwrap();
assert_that(foo.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0)
.with_stdout(""));
.file("src/lib.rs", r#"
pub fn gimme() -> &'static str { "zoidberg" }
"#)
- }).assert();
+ }).unwrap();
let repo = git2::Repository::open(&p2.root()).unwrap();
let mut cfg = repo.config().unwrap();
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "pub fn bar() -> int { 1 }")
- }).assert();
+ }).unwrap();
// Lock p1 to the first rev in the git repo
let p1 = project("p1")
"#, bar.url()).as_slice())
.file("src/main.rs", "fn main() {}");
p1.build();
- p1.root().move_into_the_past().assert();
+ p1.root().move_into_the_past().unwrap();
assert_that(p1.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(format!("\
{updating} git repository `{bar}`
// Make a commit to lock p2 to a different rev
File::create(&bar.root().join("src/lib.rs")).write_str(r#"
pub fn bar() -> int { 2 }
- "#).assert();
+ "#).unwrap();
let repo = git2::Repository::open(&bar.root()).unwrap();
add(&repo);
commit(&repo);
.file("bar/src/bar.rs.in", r#"
pub fn gimme() -> int { 0 }
"#)
- }).assert();
+ }).unwrap();
- p.root().join("bar").move_into_the_past().assert();
+ p.root().join("bar").move_into_the_past().unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0));
execs().with_stdout("0\n"));
// Touching bar.rs.in should cause the `build` command to run again.
- let mut file = fs::File::create(&p.root().join("bar/src/bar.rs.in")).assert();
- file.write_str(r#"pub fn gimme() -> int { 1 }"#).assert();
+ let mut file = fs::File::create(&p.root().join("bar/src/bar.rs.in")).unwrap();
+ file.write_str(r#"pub fn gimme() -> int { 1 }"#).unwrap();
drop(file);
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "pub fn bar() -> int { 1 }")
- }).assert();
+ }).unwrap();
let p = project("p1")
.file("Cargo.toml", format!(r#"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "fn unused() {}")
- }).assert();
+ }).unwrap();
let p = project("foo")
.file("Cargo.toml", format!(r#"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let foo2 = git_repo("foo2", |project| {
project.file("Cargo.toml", r#"
[package]
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let bar = git_repo("bar", |project| {
project.file("Cargo.toml", format!(r#"
[package]
git = '{}'
"#, foo2.url()).as_slice())
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let p = project("project")
.file("Cargo.toml", format!(r#"
authors = ["wycats@example.com"]
"#)
.file("a/src/lib.rs", "")
- }).assert();
+ }).unwrap();
let p = project("project")
.file("Cargo.toml", format!(r#"
authors = ["wycats@example.com"]
"#)
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let dep1 = git_repo("dep1", |project| {
project.file("Cargo.toml", format!(r#"
[package]
git = '{}'
"#, transitive.url()).as_slice())
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let dep2 = git_repo("dep2", |project| {
project.file("Cargo.toml", format!(r#"
[package]
git = '{}'
"#, transitive.url()).as_slice())
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let p = project("project")
.file("Cargo.toml", format!(r#"
authors = []
"#)
.file("a/src/lib.rs", "")
- }).assert();
+ }).unwrap();
let p = project("project")
.file("Cargo.toml", format!(r#"
// Just be sure to change a file
File::create(&dep.root().join("src/lib.rs")).write_str(r#"
pub fn bar() -> int { 2 }
- "#).assert();
+ "#).unwrap();
add(&repo);
commit(&repo);
authors = []
"#)
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let a2 = git_repo("a2", |project| {
project.file("Cargo.toml", r#"
[package]
authors = []
"#)
.file("src/lib.rs", "")
- }).assert();
+ }).unwrap();
let p = project("project")
.file("Cargo.toml", r#"
use std::io::{fs, File, USER_RWX};
-use support::{ResultTest, project, execs, main_file, cargo_dir};
+use support::{project, execs, main_file, cargo_dir};
use support::{COMPILING, RUNNING};
use support::paths::{mod, PathExt};
use hamcrest::{assert_that, existing_file};
// This time we shouldn't compile bar
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(""));
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
p.build(); // rebuild the files (rewriting them in the process)
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
//
// We base recompilation off mtime, so sleep for at least a second to ensure
// that this write will change the mtime.
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
File::create(&p.root().join("baz/src/baz.rs")).write_str(r#"
pub fn baz() { println!("hello!"); }
- "#).assert();
+ "#).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(format!("{} baz v0.5.0 ({})\n\
{} bar v0.5.0 ({})\n\
COMPILING, p.url())));
// Make sure an update to bar doesn't trigger baz
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
File::create(&p.root().join("bar/src/bar.rs")).write_str(r#"
extern crate baz;
pub fn bar() { println!("hello!"); baz::baz(); }
- "#).assert();
+ "#).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(format!("{} bar v0.5.0 ({})\n\
{} foo v0.5.0 ({})\n",
{} foo v0.5.0 ({})\n",
COMPILING, bar,
COMPILING, p.url())));
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
File::create(&p.root().join("src/foo.rs")).write_str(r#"
fn main() {}
- "#).assert();
+ "#).unwrap();
// This shouldn't recompile `bar`
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
"#)
.file("src/lib.rs", "");
- fs::mkdir(&paths::root().join(".cargo"), USER_RWX).assert();
+ fs::mkdir(&paths::root().join(".cargo"), USER_RWX).unwrap();
File::create(&paths::root().join(".cargo/config")).write_str(r#"
paths = ["bar"]
- "#).assert();
+ "#).unwrap();
let p = project("foo")
.file("Cargo.toml", format!(r#"
"#);
p.build();
- p.root().join("bar").move_into_the_past().assert();
+ p.root().join("bar").move_into_the_past().unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_stdout(format!("{} bar v0.5.0 ({})\n\
// Touching bar.rs.in should cause the `build` command to run again.
{
- let mut file = fs::File::create(&p.root().join("bar/src/bar.rs.in")).assert();
- file.write_str(r#"pub fn gimme() -> int { 1 }"#).assert();
+ let mut file = fs::File::create(&p.root().join("bar/src/bar.rs.in")).unwrap();
+ file.write_str(r#"pub fn gimme() -> int { 1 }"#).unwrap();
}
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
use std::io::{fs, File};
use support::{project, execs, path2url};
-use support::{COMPILING, cargo_dir, ResultTest};
+use support::{COMPILING, cargo_dir};
use support::paths::PathExt;
use hamcrest::{assert_that, existing_file};
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0).with_stdout(""));
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
- File::create(&p.root().join("src/a.rs")).write_str("fn main() {}").assert();
+ File::create(&p.root().join("src/a.rs")).write_str("fn main() {}").unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0).with_stdout(format!("\
{compiling} foo v0.0.1 ({dir})
", compiling = COMPILING, dir = path2url(p.root()))));
- fs::rename(&p.root().join("src/a.rs"), &p.root().join("src/b.rs")).assert();
+ fs::rename(&p.root().join("src/a.rs"), &p.root().join("src/b.rs")).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(101));
});
let lib = p.root().join("src/lib.rs");
let bin = p.root().join("src/b.rs");
- File::create(&lib).write_str("invalid rust code").assert();
- lib.move_into_the_past().assert();
- p.root().move_into_the_past().assert();
+ File::create(&lib).write_str("invalid rust code").unwrap();
+ lib.move_into_the_past().unwrap();
+ p.root().move_into_the_past().unwrap();
- File::create(&bin).write_str("fn foo() {}").assert();
+ File::create(&bin).write_str("fn foo() {}").unwrap();
// Make sure the binary is rebuilt, not the lib
assert_that(p.process(cargo_dir().join("cargo")).arg("build")
use std::io::File;
-use support::{project, execs, cargo_dir, ResultTest};
+use support::{project, execs, cargo_dir};
use hamcrest::assert_that;
fn setup() {}
let lockfile = p.root().join("Cargo.lock");
let lock = File::open(&lockfile).read_to_string();
- let lock = lock.assert();
+ let lock = lock.unwrap();
let lock = lock.as_slice().replace("\n", "\r\n");
- File::create(&lockfile).write_str(lock.as_slice()).assert();
+ File::create(&lockfile).write_str(lock.as_slice()).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0));
});
let lockfile = p.root().join("Cargo.lock");
let toml = p.root().join("Cargo.toml");
- let lock1 = File::open(&lockfile).read_to_string().assert();
+ let lock1 = File::open(&lockfile).read_to_string().unwrap();
// add a dep
File::create(&toml).write_str(r#"
[dependencies.bar]
path = "bar"
- "#).assert();
+ "#).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("generate-lockfile"),
execs().with_status(0));
- let lock2 = File::open(&lockfile).read_to_string().assert();
+ let lock2 = File::open(&lockfile).read_to_string().unwrap();
assert!(lock1 != lock2);
// change the dep
name = "bar"
authors = []
version = "0.0.2"
- "#).assert();
+ "#).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("generate-lockfile"),
execs().with_status(0));
- let lock3 = File::open(&lockfile).read_to_string().assert();
+ let lock3 = File::open(&lockfile).read_to_string().unwrap();
assert!(lock1 != lock3);
assert!(lock2 != lock3);
name = "foo"
authors = []
version = "0.0.1"
- "#).assert();
+ "#).unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("generate-lockfile"),
execs().with_status(0));
- let lock4 = File::open(&lockfile).read_to_string().assert();
+ let lock4 = File::open(&lockfile).read_to_string().unwrap();
assert_eq!(lock1, lock4);
});
"#;
let lockfile = p.root().join("Cargo.lock");
{
- let lock = File::open(&lockfile).read_to_string().assert();
- File::create(&lockfile).write_str((lock + metadata).as_slice()).assert();
+ let lock = File::open(&lockfile).read_to_string().unwrap();
+ File::create(&lockfile).write_str((lock + metadata).as_slice()).unwrap();
}
// Build and make sure the metadata is still there
assert_that(p.process(cargo_dir().join("cargo")).arg("build"),
execs().with_status(0));
- let lock = File::open(&lockfile).read_to_string().assert();
+ let lock = File::open(&lockfile).read_to_string().unwrap();
assert!(lock.as_slice().contains(metadata.trim()), "{}", lock);
// Update and make sure the metadata is still there
assert_that(p.process(cargo_dir().join("cargo")).arg("update"),
execs().with_status(0));
- let lock = File::open(&lockfile).read_to_string().assert();
+ let lock = File::open(&lockfile).read_to_string().unwrap();
assert!(lock.as_slice().contains(metadata.trim()), "{}", lock);
});
use std::io::fs::PathExtensions;
use std::os;
-use support::{execs, paths, cargo_dir, ResultTest};
+use support::{execs, paths, cargo_dir};
use hamcrest::{assert_that, existing_file, existing_dir, is_not};
use cargo::util::{process, ProcessBuilder};
test!(no_argument {
assert_that(cargo_process("new"),
execs().with_status(1)
- .with_stderr("Invalid arguments.
+ .with_stderr("\
Usage:
cargo new [options] <path>
cargo new -h | --help
test!(existing {
let dst = paths::root().join("foo");
- fs::mkdir(&dst, USER_RWX).assert();
+ fs::mkdir(&dst, USER_RWX).unwrap();
assert_that(cargo_process("new").arg("foo"),
execs().with_status(101)
.with_stderr(format!("Destination `{}` already exists\n",
execs().with_status(0));
let toml = td.path().join("foo/Cargo.toml");
- let toml = File::open(&toml).read_to_string().assert();
+ let toml = File::open(&toml).read_to_string().unwrap();
assert!(toml.as_slice().contains(r#"authors = ["foo"]"#));
});
execs().with_status(0));
let toml = td.path().join("foo/Cargo.toml");
- let toml = File::open(&toml).read_to_string().assert();
+ let toml = File::open(&toml).read_to_string().unwrap();
assert!(toml.as_slice().contains(r#"authors = ["foo"]"#));
});
test!(finds_author_git {
my_process("git").args(&["config", "--global", "user.name", "bar"])
- .exec().assert();
+ .exec().unwrap();
my_process("git").args(&["config", "--global", "user.email", "baz"])
- .exec().assert();
+ .exec().unwrap();
assert_that(cargo_process("new").arg("foo").env("USER", Some("foo")),
execs().with_status(0));
let toml = paths::root().join("foo/Cargo.toml");
- let toml = File::open(&toml).read_to_string().assert();
+ let toml = File::open(&toml).read_to_string().unwrap();
assert!(toml.as_slice().contains(r#"authors = ["bar <baz>"]"#));
});
test!(author_prefers_cargo {
my_process("git").args(&["config", "--global", "user.name", "bar"])
- .exec().assert();
+ .exec().unwrap();
my_process("git").args(&["config", "--global", "user.email", "baz"])
- .exec().assert();
+ .exec().unwrap();
let root = paths::root();
- fs::mkdir(&root.join(".cargo"), USER_RWX).assert();
+ fs::mkdir(&root.join(".cargo"), USER_RWX).unwrap();
File::create(&root.join(".cargo/config")).write_str(r#"
[cargo-new]
name = "new-foo"
email = "new-bar"
git = false
- "#).assert();
+ "#).unwrap();
assert_that(cargo_process("new").arg("foo").env("USER", Some("foo")),
execs().with_status(0));
let toml = paths::root().join("foo/Cargo.toml");
- let toml = File::open(&toml).read_to_string().assert();
+ let toml = File::open(&toml).read_to_string().unwrap();
assert!(toml.as_slice().contains(r#"authors = ["new-foo <new-bar>"]"#));
assert!(!root.join("foo/.gitignore").exists());
});
test!(git_prefers_command_line {
let root = paths::root();
let td = TempDir::new("cargo").unwrap();
- fs::mkdir(&root.join(".cargo"), USER_RWX).assert();
+ fs::mkdir(&root.join(".cargo"), USER_RWX).unwrap();
File::create(&root.join(".cargo/config")).write_str(r#"
[cargo-new]
git = false
name = "foo"
email = "bar"
- "#).assert();
+ "#).unwrap();
assert_that(cargo_process("new").arg("foo").arg("--git").cwd(td.path().clone())
.env("USER", Some("foo")),
assert_that(cargo_process("new").arg("foo"), execs().with_status(0));
let subpackage = paths::root().join("foo").join("components");
- fs::mkdir(&subpackage, USER_RWX).assert();
+ fs::mkdir(&subpackage, USER_RWX).unwrap();
assert_that(cargo_process("new").arg("foo/components/subcomponent"),
execs().with_status(0));
use flate2::reader::GzDecoder;
use cargo::util::process;
-use support::{project, execs, cargo_dir, ResultTest, paths, git};
+use support::{project, execs, cargo_dir, paths, git};
use support::{PACKAGING, VERIFYING, COMPILING, ARCHIVING};
use hamcrest::{assert_that, existing_file};
assert_that(p.process(cargo_dir().join("cargo")).arg("package"),
execs().with_status(0).with_stdout(""));
- let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).assert();
+ let f = File::open(&p.root().join("target/package/foo-0.0.1.crate")).unwrap();
let mut rdr = GzDecoder::new(f);
- let contents = rdr.read_to_end().assert();
+ let contents = rdr.read_to_end().unwrap();
let ar = Archive::new(MemReader::new(contents));
- for f in ar.files().assert() {
- let f = f.assert();
+ for f in ar.files().unwrap() {
+ let f = f.unwrap();
let fname = f.filename_bytes();
assert!(fname == b"foo-0.0.1/Cargo.toml" ||
fname == b"foo-0.0.1/src/main.rs",
use tar::Archive;
use url::Url;
-use support::{ResultTest, project, execs};
+use support::{project, execs};
use support::{UPDATING, PACKAGING, UPLOADING};
use support::paths;
use support::git::repo;
fn setup() {
let config = paths::root().join(".cargo/config");
- fs::mkdir_recursive(&config.dir_path(), io::USER_DIR).assert();
+ fs::mkdir_recursive(&config.dir_path(), io::USER_DIR).unwrap();
File::create(&config).write_str(format!(r#"
[registry]
index = "{reg}"
token = "api-token"
- "#, reg = registry()).as_slice()).assert();
- fs::mkdir_recursive(&upload_path().join("api/v1/crates"), io::USER_DIR).assert();
+ "#, reg = registry()).as_slice()).unwrap();
+ fs::mkdir_recursive(&upload_path().join("api/v1/crates"), io::USER_DIR).unwrap();
repo(®istry_path())
.file("config.json", format!(r#"{{
use cargo::util::{process, ProcessBuilder};
use support::UPDATING;
-use support::{ResultTest, execs, cargo_dir};
+use support::{execs, cargo_dir};
use support::paths;
use support::git::repo;
fn setup() {
let config = paths::root().join(".cargo/config");
- fs::mkdir_recursive(&config.dir_path(), io::USER_DIR).assert();
+ fs::mkdir_recursive(&config.dir_path(), io::USER_DIR).unwrap();
File::create(&config).write_str(format!(r#"
[registry]
index = "{reg}"
- "#, reg = registry()).as_slice()).assert();
- fs::mkdir_recursive(&api_path().join("api/v1"), io::USER_DIR).assert();
+ "#, reg = registry()).as_slice()).unwrap();
+ fs::mkdir_recursive(&api_path().join("api/v1"), io::USER_DIR).unwrap();
repo(®istry_path())
.file("config.json", format!(r#"{{
use std::str;
use support::{project, execs, basic_bin_manifest, basic_lib_manifest};
-use support::{COMPILING, cargo_dir, ResultTest, RUNNING, DOCTEST};
+use support::{COMPILING, cargo_dir, RUNNING, DOCTEST};
use support::paths::PathExt;
use hamcrest::{assert_that, existing_file};
use cargo::util::process;
#[test] fn test_test() { foo::foo() }
"#);
- let output = p.cargo_process("test").exec_with_output().assert();
- let output = str::from_utf8(output.output.as_slice()).assert();
+ let output = p.cargo_process("test").exec_with_output().unwrap();
+ let output = str::from_utf8(output.output.as_slice()).unwrap();
assert!(output.contains("test bin_test"), "bin_test missing\n{}", output);
assert!(output.contains("test lib_test"), "lib_test missing\n{}", output);
assert!(output.contains("test test_test"), "test_test missing\n{}", output);
}
"#);
- let output = p.cargo_process("test").exec_with_output().assert();
- let output = str::from_utf8(output.output.as_slice()).assert();
+ let output = p.cargo_process("test").exec_with_output().unwrap();
+ let output = str::from_utf8(output.output.as_slice()).unwrap();
assert!(output.contains("main_test ... ok"), "no main_test\n{}", output);
assert!(output.contains("test_test ... ok"), "no test_test\n{}", output);
});
compiling = COMPILING, running = RUNNING,
doctest = DOCTEST,
dir = p.url()).as_slice()));
- p.root().move_into_the_past().assert();
+ p.root().move_into_the_past().unwrap();
assert_that(p.process(cargo_dir().join("cargo")).arg("test"),
execs().with_status(0)
.with_stdout(format!("\
use cargo::core::shell::{Shell,ShellConfig};
-use support::{ResultTest,Tap,shell_writes};
+use support::{Tap, shell_writes};
fn setup() {
}
let (tx, mut rx) = pair();
Shell::create(box tx, config).tap(|shell| {
- shell.say("Hey Alex", color::RED).assert();
+ shell.say("Hey Alex", color::RED).unwrap();
});
let buf = rx.read_to_end().unwrap();
let (tx, mut rx) = pair();
Shell::create(box tx, config).tap(|shell| {
- shell.say("Hey Alex", color::RED).assert();
+ shell.say("Hey Alex", color::RED).unwrap();
});
let buf = rx.read_to_end().unwrap();
assert_that(buf.as_slice(), shell_writes("Hey Alex\n"));
let (tx, mut rx) = pair();
Shell::create(box tx, config).tap(|shell| {
- shell.say("Hey Alex", color::RED).assert();
+ shell.say("Hey Alex", color::RED).unwrap();
});
let buf = rx.read_to_end().unwrap();
assert_that(buf.as_slice(),
shell_writes(colored_output("Hey Alex\n",
- color::RED).assert()));
+ color::RED).unwrap()));
});
fn colored_output<S: Str>(string: S, color: color::Color) -> IoResult<String> {